/*
 * JSF Toolkit Component Framework
 * Copyright (C) 2007 Noah Sloan <iamnoah A-T gmail D0T com>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 */
package com.jsftoolkit.gen.config.impl;

import static com.jsftoolkit.gen.config.DomUtils.findOrCreateElement;
import static com.jsftoolkit.gen.config.DomUtils.setElementValue;

import java.util.Set;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.jsftoolkit.gen.config.TldEditor;
import com.jsftoolkit.utils.Utils;

public class TldEditorImpl extends XmlEditor implements TldEditor {

	private XPathExpression existingTldTag;

	private XPathExpression attributeElement;

	private XPathExpression dvElement;

	public static final Set<String> IGNORE = Utils.asSet("componentType",
			"rendererType");

	public TldEditorImpl() throws ParserConfigurationException,
			XPathExpressionException {
		super();

		existingTldTag = xpathFactory.newXPath().compile(
				"/taglib/tag[child::name[normalize-space()=$tag]]");

		attributeElement = xpathFactory.newXPath().compile(
				"attribute[child::name[normalize-space()=$name]][1]");

		dvElement = xpathFactory.newXPath().compile("deferred-value[1]");
	}

	public Element registerAttribute(Element tag, String name, Class<?> type,
			boolean required) throws XPathExpressionException {
		return createOrUpdateAttrib(tag.getOwnerDocument(), tag, name, type,
				required);
	}

	public Element registerTag(Document doc, String tagName, String tagClass)
			throws XPathExpressionException {
		vars.get().clear();
		vars.get().put("tag", tagName);

		Element tag = findOrCreateElement(doc, doc.getDocumentElement(),
				existingTldTag, "tag", null);

		setElementValue(doc, tag, "name", tagName);
		setElementValue(doc, tag, "tag-class", tagClass);
		// TODO retain the user provided body-content (only set if non-existant)
		setElementValue(doc, tag, "body-content", "JSP");

		return tag;
	}

	/**
	 * Updates a TLD tag attribute element.
	 * 
	 * @param taglib
	 * @param tag
	 * @param attrib
	 * @param required
	 * @param elAllowed
	 * @return
	 * @throws XPathExpressionException
	 */
	protected Element createOrUpdateAttrib(Document taglib, Element tag,
			String attrib, Class<?> type, boolean required)
			throws XPathExpressionException {
		if (IGNORE.contains(attrib)) {
			return null;
		}
		vars.get().put("name", attrib);
		Element a = findOrCreateElement(taglib, tag, attributeElement,
				"attribute", null);
		setElementValue(taglib, a, "name", attrib);
		setElementValue(taglib, a, "required", Boolean.toString(required));

		if (type == null) {
			setElementValue(taglib, a, "rtexprvalue", Boolean.toString(true));
		} else {
			Element dv = findOrCreateElement(taglib, a, dvElement,
					"deferred-value", null);
			setElementValue(taglib, dv, "type", type.getName());
		}

		return a;
	}
}
